import * as THREE from "three";
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js';
import { Line2 } from 'three/examples/jsm/lines/Line2.js';
import * as d3 from "d3";
import { getDepth } from "../map"
import * as material from "../material"

// d3.geoMercator()是一个地理投影函数，用于将地球表面的经纬度坐标映射到二维平面上。
export const offsetXY = d3.geoMercator()

export let pointList = []

const texture = new THREE.TextureLoader()

// ^ 以下为可以复用的材质或模型
// 图标模型
const icon = new THREE.Sprite(new THREE.SpriteMaterial({
  map: texture.load(require('@/images/map/mark.png')), // 设置精灵纹理贴图
  transparent: true,
}));
// 创建地图
export const createMap = (data) => {
  pointList = []
  const map = new THREE.Group();
  map.name = '地图'
  // 在createMap中新增获取第一个子数据的centroid以及偏移代码，这里的centroid也就是当前地图的质心。
  // const center = [108, 34]
  const center = data.features[0].properties.centroid
  // .center(center) 用于指定投影的中心点，这个中心点决定了投影的中心位置，地图上的所有要素都将以该点为中心进行投影转换。
  offsetXY.center(center).translate([0, 0])
  data.features.forEach((feature) => {
    if (!feature.properties.level) return;
    // 创建一个对象 unit
    const unit = new THREE.Object3D();
    const { centroid, center, name, adcode } = feature.properties;
    const { coordinates, type } = feature.geometry;

    let depth = 1;
    const point = centroid || center || [0, 0];
    // 添加的自定义属性
    unit.self = { name, adcode, point: offsetXY(point), ...feature.properties } // 从接口获取的地理数据
    coordinates.forEach((coordinate) => {
      // ^ 注意在geometry(几何体)中的类型分为MultiPolygon和Polygon，需要分别处理，不然会造成个别区域缺失
      // 二者区别是MultiPolygon的坐标多一层嵌套数据，所以这里多做一次遍历。
      if (type === "MultiPolygon") coordinate.forEach((item) => fn(item));
      if (type === "Polygon") fn(coordinate);
      // 根据 coordinate(坐标) 建立模型
      function fn(coordinate) {
        // 绘制网格模型
        const mesh = createMesh(coordinate, depth);
        // 绘制描边
        const line = createLine(coordinate, depth)
        mesh.name = name
        pointList.push(coordinate)
        unit.add(mesh, ...line,);
      }
    });
    unit.name = name
    map.add(unit);
  });
  return map;
};

// data -> 二维向量的数组：一组二维向量表示一个多边形轮廓坐标
export const createMesh = (data, depth = 1, color) => {
  // 多边形轮廓绘制 Shape
  const shape = new THREE.Shape();
  data.forEach((item, idx) => {
    const [x, y] = offsetXY(item)
    if (idx === 0) shape.moveTo(x, -y);
    else shape.lineTo(x, -y);
  });
  // 轮廓填充 ShapeGeometry
  // const shapeGeometry = new THREE.ShapeGeometry(shape); // 此图形为二维图形
  // ^ 通过 THREE.ExtrudeGeometry将shape从二维挤出成三维
  const shapeGeometry = new THREE.ExtrudeGeometry(shape, {
    depth: depth, // 图形挤出的深度，默认值为1
    bevelEnabled: false, // 对挤出的形状应用是否斜角，默认值为true
  });
  const mesh = new THREE.Mesh(shapeGeometry, [material.topFace.clone(), material.side.clone()]);
  mesh.colorName = 'mapMesh'
  return mesh
};

// 描边
export const createLine = (data, depth = 1,) => {
  const points = [];
  data.forEach((item) => {
    const [x, y] = offsetXY(item);
    points.push(x, -y, 0)
  });
  const geometry = new LineGeometry();
  geometry.setPositions(points);
  const upLine = new Line2(geometry, material.upLine.clone());
  upLine.isUpLine = true
  upLine.colorName = 'upLine'
  upLine.name = 'mapLine'
  const downLine = new Line2(geometry, material.downLine.clone());
  downLine.isDownLine = true
  downLine.colorName = 'downLine'
  downLine.name = 'mapLine'
  upLine.computeLineDistances();
  downLine.computeLineDistances();
  upLine.position.z = depth + 0.0001;
  downLine.position.z = - 0.1905;
  return [upLine, downLine];
};

// 绘制图标
export const createIcon = (point, size,) => {
  const { depth } = getDepth(size)
  const newIcon = icon.clone()
  newIcon.scale.set(depth / 2, depth / 2, depth / 2); // 大小缩放
  // 设置精灵模型位置
  const [x, y] = point;
  newIcon.name = 'mark'
  // newIcon.self = self
  newIcon.position.set(x - depth * 0.2, -y, depth * 1.2);
  return newIcon;
};
